Resource Manager Pattern

In Embedded and Realtime Systems, there occur many instances of Resource management. Most commonly used design pattern to manage resources of a specific type is the Resource Manager Pattern. This pattern is described using a standard pattern definition template.

This design pattern implementation uses STL (Standard Template Library), so please review the following articles before this one:

Intent

The main intention here is to manage multiple resources of the same type. To maintain the status of managed resources, a resource manager is implemented that maintains two lists of resources. Free list contains all the resources that are free. Busy list contains all the resources that are busy. A resource allocation request is serviced by the resource manager by allocating a resource from the free list and putting it in the busy list. Similarly, a resource release request is serviced by the resource manager by inserting the freed resource to the free list.

Also Known As

Motivation

The resource manager design pattern implements a centralized management strategy for resource usage. Looking at the free and busy lists of resources gives a clear picture of the current resource usage in the system. Using the resource manager, the application can quickly figure out all allocated resources in the system. This information helps in implementing audits also. 

Applicability

The resource manager design pattern finds applicability in situations where centralized management of multiple resources of same type is involved.

Structure

The resource manager keeps two lists, one for busy resources and one for free resources. Internally the free list may be maintained as a stack if hottest resource first type of scenario needs to be implemented. If a coldest resource first type of scenario is to be implemented, the free list may be maintained as a queue. The busy list is maintained as a STL map so that resources can be quickly accessed. (The map is keyed with the resource-id, a unique number assigned to every resource) 

Participants

The key actors of this design pattern:

Collaboration

The following diagram shows the relationship and collaboration between various classes involved in the Resource Manager Pattern. Points to note are:

Resource Manager UML Class Diagram

Consequences

When Resource Manager Pattern is used, the programmer always has access to all the resources. Thus any action on resources can be initiated from the Resource Manager, instead of handling it separately in all objects that allocate resources. 

Implementation

The following scenarios are supported by the Resource Manager:

Allocating a Resource

  1. A system entity sends a request for a resource to resource manager.
  2. The resource manager allocates a resource from the FreeResourceQueue.
  3. The resource manager removes the resource from the FreeResourceQueue.
  4. The resource manager adds the resource to the BusyResourceMap.
  5. The resource manager responds to system entity with the pointer of the allocated resource.

Freeing a Resource

  1. A system entity sends a resource release request to the resource manager.
  2. The resource manager removes the resource from the BusyResourceMap.
  3. The resource manager adds the resource to the FreeResourceQueue.

Adding a Resource

  1. When a resource is created, it is added to the FreeResourceQueue.

Removing a Resource

  1. Check if the resource is present in the BusyResourceMap.
  2. If the resource is present, inform resource about the forced release (if the resource is currently in use, the application using the resource needs to be notified)
  3. Remove the resource from the BusyResourceMap.
  4. If the resource is not present in the BusyResourceMap, remove the resource from the FreeResourceQueue.

Sample Code and Usage

Here is the code for a typical implementation of this pattern using STL:

Resource Manager
#include <queue>           // STL header file for queue
#include <map>             // Header file for map
using namespace std;       // Specify that we are using the std namespace

// Resource Id: A unique id assigned to every resource 
typedef int ResourceId;

class ResourceManager
{
   // Declaring the type for a queue. Here we are specifying
   // a queue of Resource pointers organized as a linked list.
   typedef queue<Resource *>, list<Resource *> > FreeResourceQueue;
   FreeResourceQueue m_freeResourceQueue;
      
   // Map is used to keep track of the busy resources.
   typedef map <Resource *, ResourceId> BusyResourceMap;
   BusyResourceMap m_busyResourceMap;
public:
   
   ResourceManager(int resourceCount, Resource *resourceArray)
   {
      // Add all the resources that have been specified at construction time
      for (int i = 0; i < resourceCount; i++)
      {
         Add(resourceArray[i]);
      }
   }
   // Allocate a free resource by removing it from the
   // the free resource queue. Returns NULL if no resource is found
   Resource * Allocate()
   {
      Resource *pResource = NULL;
      
      // Check if any free resources are available.
      if (!m_freeResourceQueue.empty())
      {
         // Queue is not empty so get a pointer to the
         // first resource in the queue
         pResource = m_freeResourceQueue.front();
         
         // Now remove the pointer from the free resource queue
         m_freeResourceQueue.pop();
         
         // Next step is to add the resource to the busy map ...
         // Obtain the resource id
         ResourceId resId = pResource->GetResourceId();
         
         // Make sure that the resource is not already present in the map
         if (m_busyResourceMap.count(resId) == 0)
         {
            m_busyResourceMap[resId] = pResource;
         }
      }
      return pResource;
   }
   
   // Free a resource by adding it back into the free resource list
   void Free(Resource *pResource)
   {
      // Obtain the resource Id
      ResourceId resId = pResource->GetResourceId();
      
      // Remove the resource from the busy resource map
      m_busyResourceMap.erase(resId);
      
      // Insert the resource at the end of the free queue
      m_freeResourceQueue.push(pResource);
   }
      
   // Obtain the total count of free resources
   int GetFreeResourceCount() const
   {
      return m_freeResourceQueue.size();
   }   
   
   int GetBusyResourceCount() const
   {
      return m_busyResourceMap.size();
   }
   
   // Adding a new resource to the resource manager.
   void Add(Resource *pResource)
   {
     // A new resource is assumed to be free, hence it is 
     // added to the free queue
     m_freeResourceQueue.push(pResource);
   }
   
   // Remove the resource from the resource manager
   void Remove(Resource *pResource)
   {
     // Obtain the resource id
     ResourceId resId = pResource->GetResourceId();
         
     // Check if the resource is present in the map
     // i.e. the resource is currently busy
     if (m_busyResourceMap.count(resId))
     {
       // This resource is currently in use, so inform
       // the Resource object about this release. Resource
       // will inform the application about the forced release
       pResource->HandleForcedRelease();
     	
       // Remove the resource from the busy resource map
       m_busyResourceMap.erase(resId);
     }
     else
     {
       // remove the pointer from the free resource queue
       m_freeResourceQueue.erase(resId);
     }
   }
};

Known Uses

Any application where resources need to be managed. A few examples of a Resource Manager use are:

Related Patterns